package com.example.okhttps;

import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

import androidx.fragment.app.Fragment;

import com.ejlchina.okhttps.HTTP;
import com.ejlchina.okhttps.HttpResult;
import com.ejlchina.okhttps.HttpTask;
import com.ejlchina.okhttps.OnCallback;
import com.example.data.Token;
import com.example.kits.Main;
import com.example.kits.Tip;
import com.example.ui.LoginActivity;

public class Config implements com.ejlchina.okhttps.Config {

    @Override
    public void with(HTTP.Builder builder) {
        builder.baseUrl(Urls.BASE_URL)
                .callbackExecutor(Main::run)
                .addPreprocessor(chain -> {
                    HttpTask<?> task = chain.getTask();
                    if (task.isTagged(Tags.LOADING)) {
                        Tip.showLoading(ctx(task));
                    }
                    chain.proceed();
                })
                .addPreprocessor(chain -> {
                    HttpTask<?> task = chain.getTask();
                    Object bound = task.getBound();
                    task.bind(new LcObserver(task, bound));
                    chain.proceed();
                })
                .addSerialPreprocessor(chain -> {
                    HttpTask<?> task = chain.getTask();
                    // 根据标签判断是否需要 Token
                    if (!task.isTagged(Tags.TOKEN)) {
                        chain.proceed();
                        return;
                    }
                    Context ctx = ctx(task);
                    requestToken(ctx, chain.getHttp(), token -> {
                                if (token != null) {
                                    task.addHeader("Access-Token", token);
                                } else {
                                    ctx.startActivity(new Intent(ctx, LoginActivity.class));
                                }
                                chain.proceed();
                            });
                })
                // 错误码统一处理
                .responseListener((HttpTask<?> task, HttpResult result) -> {
                    // 刷新 Token 的接口可以例外
                    if (task.getUrl().contains(Urls.TOKEN_REFRESH)
                            || result.isSuccessful()) {
                        // 这里演示的是 HTTP 状态码的处理，如果有自定义的 code, 也可以进行深层次的判断
                        return true;            // 继续接口的业务处理
                    }
                    // 向用户展示接口的错误信息
                    Tip.toast(ctx(task), result.getBody().toString());
                    return false;               // 阻断
                })
                // 生命周期绑定：第三步
                .completeListener((HttpTask<?> task, HttpResult.State state) -> {
                    Object bound = task.getBound();
                    if (bound instanceof LcObserver) {
                        ((LcObserver) bound).unbind();
                    }
                    // 网络错误统一处理
                    switch (state) {
                        case TIMEOUT:
                            Tip.toast(ctx(task), "网络连接超时");
                            break;
                        case NETWORK_ERROR:
                            Tip.toast(ctx(task),"网络错误，请检查WIFI或数据是否开启");
                            break;
                        case EXCEPTION:
                            Tip.toast(ctx(task),"接口请求异常: " + task.getUrl());
                            break;
                    }
                    if (task.isTagged(Tags.LOADING)) {
                        Tip.hideLoading();    // 关闭加载框
                    }
                    return true;
                });
    }


    private Context ctx(HttpTask<?> task) {
        Object bound = task.getBound();
        if (bound instanceof LcObserver) {
            bound = ((LcObserver) bound).getBound();
        }
        if (bound instanceof Context) {
            return (Context) bound;
        }
        if (bound instanceof Fragment) {
            return ((Fragment) bound).getActivity();
        }
        // 还可以添加更多获取 Context 的策略，比如从全局 Application 里取
        throw new IllegalStateException("没有绑定 Context 对象！");
    }

    /**
     * 获取TOKEN，若过期则刷新（代码中的字符串可以替换为常量）
     **/
    private void requestToken(Context ctx, HTTP http, OnCallback<String> callback) {
        Token token = Token.fromSp(ctx);
        if (token == null) {
            callback.on(null);
            return;
        }
        if (token.isValid()) {
            callback.on(token.getAccessToken());
            return;
        }
        // 访问令牌已过期，刷新令牌未过期，则调接口刷新当前令牌
        http.async(Urls.TOKEN_REFRESH)
                .skipPreproc()      // 跳过所有预处理器
                .addBodyPara("refreshToken", token.getRefreshToken())
                .setOnResponse(res -> {
                    if (!res.isSuccessful()) {
                        callback.on(null);
                        return;
                    }
                    Token newToken = res.getBody().toBean(Token.class);
                    if (!newToken.saveToSp(ctx)) {
                        Toast.makeText(ctx, "令牌保存失败", Toast.LENGTH_LONG).show();
                    }
                    callback.on(newToken.getAccessToken());
                })
                .setOnException(e -> callback.on(null))
                .post();
    }

}
